#include "stk_message_base.h"
#include "stk_const.h"
#include "stk_utility.h"
#include <string.h>
#include <mutex>
#include <algorithm>

using namespace stk;

bool MsgBase::m_config = false;

static std::mutex init_mtx;
typedef struct ___stk_message_config_t
{
    const char * hdrname;
    int32_t (MsgBase::*setheader)(const char *);
}
__stk_message_config_t;

static int new_hdr_ref_table[HASH_TABLE_SIZE] = {0};     /* the hashtable contains indices to the pconfig table    */
static __stk_message_config_t header_pconfig[NUMBER_OF_HEADERS] =
{
    {STK_COMM_ACCEPT,            &MsgBase::SetAccept},
    {STK_COMM_ACCEPT_ENCODING,   &MsgBase::SetAcceptEncoding},
    {STK_COMM_ACCEPT_LANGUAGE,	 &MsgBase::SetAcceptLanguage},
    {STK_COMM_AUTHORIZATION,     &MsgBase::SetAuthorization},
    {STK_COMM_CSEQ,              &MsgBase::SetCSeq},

    {STK_COMM_CONTENT_ENCODING,  &MsgBase::SetContentEncoding},
    {STK_COMM_CONTENT_TYPE,      &MsgBase::SetContentType},
    {STK_COMM_CONTENT_LENGTH,    &MsgBase::SetContentLength},
    {STK_COMM_CONTENT_LANGUAGE,  &MsgBase::SetContentLanguage},
    {STK_COMM_CONTENT_BASE,      &MsgBase::SetContentBase},

    {STK_COMM_DATE,              &MsgBase::SetDate},
    {STK_COMM_USER_AGENT,        &MsgBase::SetUserAgent},
    {STK_COMM_SERVER,            &MsgBase::SetServer},
    {STK_COMM_PUBLIC,            &MsgBase::SetPublic},
    {STK_HTTP_HOST,              &MsgBase::SetHost},

    {STK_HTTP_CONNECTION,        &MsgBase::SetConnection},
    {STK_HTTP_LOCATION,          &MsgBase::SetLocation},
    {STK_COMM_WWW_AUTHENTICATE,  &MsgBase::SetWwwAuthenticate},
    {STK_COMM_CACHE_CONTROL,     &MsgBase::SetCacheControl},
    {STK_RTSP_TRANSPORT,         &MsgBase::SetTransport},

    {STK_RTSP_SESSION,           &MsgBase::SetSession},
    {STK_COMM_RANGE,             &MsgBase::SetRange},
    {STK_RTSP_SCALE,             &MsgBase::SetScale},
    {STK_HTTP_ORIGIN,            &MsgBase::SetOrigin},
    {STK_HTTP_CORS_ORIGIN,       &MsgBase::SetCorsOrigin},

    {STK_HTTP_CORS_HEADERS,      &MsgBase::SetCorsHeader},
    {STK_HTTP_CORS_METHODS,      &MsgBase::SetCorsMethod},
    {STK_COMM_ALLOW,             &MsgBase::SetAllow},
    {STK_HTTP_WEBSOCK_KEY,       &MsgBase::SetWebsockKey},
    {STK_HTTP_WEBSOCK_ACCPET,    &MsgBase::SetWebsockAccept},

    {STK_HTTP_WEBSOCK_VERSION,   &MsgBase::SetWebsockVersion},
    {STK_HTTP_WEBSOCK_EXTENSIONS,&MsgBase::SetWebsockExtensions},
    {STK_HTTP_UPGRADE,           &MsgBase::SetUpgrade},
};

MsgBase::MsgBase()
{
    init();
}

MsgBase::~MsgBase()
{
    clear();
}

MsgBase & MsgBase::operator= (const MsgBase &src)
{
    if (this == &src)
    {
        return *this;
    }

    clear();

    m_bValid         = src.m_bValid;
    m_iMsgType       = src.m_iMsgType;
    m_iStatusCode    = src.m_iStatusCode;
    m_strMethod      = src.m_strMethod;
    m_strReqUrl      = src.m_strReqUrl;
    m_iContentLength = src.m_iContentLength;

    cseq             = src.cseq;
    content_type     = src.content_type;
    content_length   = src.content_length;

    bodies.assign(src.bodies, _override_t<Body>());

    m_iMessageProperty = src.m_iMessageProperty;

    /* 只有结构和内容匹配的时候才复制内容 */
    if (m_iMessageProperty == 1)
    {
        m_strMessage = src.m_strMessage;
    }

    return *this;
}

void MsgBase::init()
{
    m_bValid           = false;
    m_iMsgType         = MSG_TYPE_HTTP;
    m_iStatusCode      = 0;
    m_strMethod        = "";
    m_strReqUrl        = "";
    m_strReasonPhrase  = "";
    m_strMessage       = "";
    m_iMessageProperty = 2;
    m_iContentLength   = 0;

    std::lock_guard<std::mutex> locker(init_mtx);

    if (!m_config)
    {
        int i;

        /* initialize the table */
        for (i = 0; i < HASH_TABLE_SIZE; i++)
        {
            new_hdr_ref_table[i] = -1;    /* -1 -> no entry */
        }

        for (i = 0; i < NUMBER_OF_HEADERS; i++)
        {
            unsigned int hash;

            /* calculate hash value using lower case */
            /* Fixed: do not lower constant... osip_tolower( new_pconfig[i].hname ); */
            string pname = header_pconfig[i].hdrname;
            transform(pname.begin(), pname.end(), pname.begin(), ::tolower);
            hash = Hash(pname.c_str());
            hash = hash % HASH_TABLE_SIZE;

            if (new_hdr_ref_table[hash] == -1)
            {
                /* store reference(index) to new_pconfig table */
                new_hdr_ref_table[hash] = i;
            }
            else
            {
                /* oops, conflict!-> change the hash table or use another hash function size */
                printf("哈希表的当前大小出现哈希冲突\n");
                abort();
                return;
            }
        }

        m_config = true;
    }
}

/* ---For better performance---
   Calculates a hash value for the given string */
uint32_t MsgBase::Hash(const char *str)
{
    unsigned int hash = 5381;
    int c;

    while ((c = *str++) != '\0')
    {
        hash = ((hash << 5) + hash) + c;
    }

    return hash;
}


void  MsgBase::clear()
{
    m_bValid           = false;
    m_iStatusCode      = 0;
    m_strMethod        = "";
    m_strReqUrl        = "";
    m_strReasonPhrase  = "";
    m_strMessage       = "";
    m_iMessageProperty = 2;
    m_iContentLength   = 0;

    cseq.clear();
    content_type.clear();
    content_length.clear();

    bodies.clear();
}

int32_t MsgBase::MakeStartLineString(string &str)
{
    if (m_strMethod.size() > 0 &&
            m_strReqUrl.size() > 0)
    {
        str += m_strMethod + " " + m_strReqUrl + " " + m_strVersion;

        return 0;;
    }

    if (m_iStatusCode != 0)
    {
        char szStatusCode[10] = "";

        if ((m_strReasonPhrase.size() == 0)	||
                (m_iStatusCode < 100) ||
                (m_iStatusCode > 699))
        {
            return -1;
        }

        snprintf(szStatusCode, sizeof(szStatusCode) - 1, "%u", m_iStatusCode);

        str += m_strVersion + " " + szStatusCode + " " + m_strReasonPhrase;
        return 0;
    }

    return -1;
}

int32_t MsgBase::MakeFieldString(MsgField &cField, const string strFieldHeader, string &strField)
{
    if (cField.isvalid())
    {
        string str;
        int32_t ret = cField.to_str(str);

        if (ret != 0)
        {
            return -1;
        }

        strField += strFieldHeader + str + CRLF;
    }

    return 0;
}

int32_t MsgBase::MakeSingleLineFieldString(MsgFieldList &listField, const string strFieldHeader, string &strField)
{
    int pos = 0;

    while (!listField.eol(pos))
    {
        strField += strFieldHeader;

        while (!listField.eol(pos))
        {
            MsgField *elt = (MsgField *)listField.get(pos);

            if (elt->to_str(strField) != 0)
            {
                return -1;
            }

            pos++;

            if (!listField.eol(pos))
            {
                if (0 == strncmp(STK_RTSP_TRANSPORT, strFieldHeader.c_str(), 9))
                {
                    strField += "; ";
                }
                else
                {
                    strField += ", ";
                }
            }
        }

        strField += CRLF;
    }

    return 0;
}

int32_t MsgBase::MakeMultiLineFieldString(MsgFieldList &listField, const string strFieldHeader, string &strField)
{
    int pos = 0;

    while (!listField.eol(pos))
    {
        MsgField *elt = (MsgField *)listField.get(pos);

        string str;

        if (elt->to_str(str) != 0)
        {
            return -1;
        }

        strField += strFieldHeader + str + CRLF;

        pos++;
    }

    return 0;
}

int32_t MsgBase::msg_headers_parse(const char *start_of_header, const char **body)
{
    const char *colon_index;      /* index of ':' */
    const char *end_of_header;

    for (;;)
    {
        if (start_of_header[0] == '\0')
        {
            /* final CRLF is missing */
            /* printf("MsgBase::msg_headers_parse:SIP message does not end with CRLFCRLF\n"); */
            return 0;
        }

        if (stk_find_next_crlf(start_of_header, &end_of_header) != 0)
        {
            /* printf("MsgBase::msg_headers_parse:End of header Not found\n"); */
            return -1;            /* this is an error case!     */
        }

        /* the list of headers MUST always end with  */
        /* CRLFCRLF (also CRCR and LFLF are allowed) */
        if ((start_of_header[0] == '\r') || (start_of_header[0] == '\n'))
        {
            *body = start_of_header;
            return 0;             /* end of header found        */
        }

        /* find the header name */
        colon_index = strchr(start_of_header, ':');

        if (colon_index == NULL)
        {

            /* printf("MsgBase::msg_headers_parse:End of header Not found while finding header name\n"); */
            return -1;            /* this is also an error case */
        }

        if (colon_index - start_of_header + 1 < 2)
        {
            return -1;
        }

        if (end_of_header <= colon_index)
        {
            printf("MsgBase::msg_headers_parse:Malformed message\n");
            return -1;
        }

        char szHeaderName[1024] = "";
        char szHeaderValue[1024] = "";

        if (colon_index - start_of_header >= 1024)
        {
            printf("MsgBase::msg_headers_parse:Header too long\n");
            return -1;
        }

        stk_clrncpy(szHeaderName, start_of_header, colon_index - start_of_header);
        {
            const char *end;

            /* END of header is (end_of_header-2) if header separation is CRLF */
            /* END of header is (end_of_header-1) if header separation is CR or LF */
            if ((end_of_header[-2] == '\r') || (end_of_header[-2] == '\n'))
            {
                end = end_of_header - 2;
            }
            else
            {
                end = end_of_header - 1;
            }

            if (end - colon_index < 2 || end - colon_index - 1 >= 1024)
            {
                szHeaderValue[0] = 0;    /* some headers (subject) can be empty */
            }
            else if (end - colon_index - 1 >= 1024)
            {

                printf("MsgBase::msg_headers_parse:Header value too long\n");
                return -1;
            }
            else
            {
                stk_clrncpy(szHeaderValue, colon_index + 1, end - colon_index - 1);
            }
        }


        /* hvalue MAY contains multiple value. In this case, they   */
        /* are separated by commas. But, a comma may be part of a   */
        /* quoted-string ("here, and there" is an example where the */
        /* comma is not a separator!) */
        if (msg_set_multiple_header(szHeaderName, szHeaderValue) != 0)
        {
            /* printf("MsgBase::msg_headers_parse:End of header Not found\n"); */
            return -1;
        }


        /* continue on the next header */
        start_of_header = end_of_header;
    }

    /* Unreachable code */

    printf("MsgBase::msg_headers_parse:This code cannot be reached\n");
    return 0;
}


int32_t MsgBase::msg_body_parse(const char *start_of_buf, const char **next_body, size_t length)
{
    const char *start_of_body;
//	const char *end_of_body;
//	const char *end_of_buf;

    if (content_type.m_strType.empty() ||
            content_type.m_strSubType.empty())
    {
        return 0;                   /* no body is attached */
    }

    if (0 != strcasecmp(content_type.m_strType.c_str(), "multipart"))
    {
        size_t body_len;

        if (start_of_buf[0] == '\0')
        {

            printf("MsgBase::msg_body_parse:final CRLF is missing\n");
            return -1;              /* final CRLF is missing */
        }

        /* get rid of the first CRLF */
        if ('\r' == start_of_buf[0])
        {
            if ('\n' == start_of_buf[1])
            {
                start_of_body = start_of_buf + 2;
            }
            else
            {
                start_of_body = start_of_buf + 1;
            }
        }
        else if ('\n' == start_of_buf[0])
        {
            start_of_body = start_of_buf + 1;
        }
        else
        {
            printf("MsgBase::msg_body_parse:message does not end with CRLFCRLF, CRCR or LFLF\n");
            return -1;              /* message does not end with CRLFCRLF, CRCR or LFLF */
        }

        /* update length (without CRLFCRLF */
        length = length - (start_of_body - start_of_buf); /* fixed 24 08 2004 */

        if (length <= 0)
        {

            printf("MsgBase::msg_body_parse:length error!\n");
            return -1;
        }

        if (m_iContentLength != 0)
        {
            /* fix when content length not equal real length */
            if (length != (uint32_t)m_iContentLength)
            {
                body_len = length;
            }
            else
            {
                body_len = m_iContentLength;
            }
        }
        else
        {
            /* if content_length does not exist, set it. */

            /* case where content-length is missing but the
               body only contains non-binary data */
            if (0 == strcasecmp(content_type.m_strType.c_str(), "application") &&
                    (0 == strcasecmp(content_type.m_strSubType.c_str(), "sdp") ||
                     0 == strcasecmp(content_type.m_strSubType.c_str(), "xml") ||
                     0 == strcasecmp(content_type.m_strSubType.c_str(), "json") ||
                     0 == strcasecmp(content_type.m_strSubType.c_str(), "javascript")
                    ))
            {
                body_len = strlen(start_of_body);

                if (SetContentLength(body_len) < 0)
                {
                    return -1;
                }
            }
            else
            {
                printf("MsgBase::msg_body_parse:Content-type may be non binary data!\n");
                return -1;
            }
        }

        if (length < body_len)
        {
            printf("MsgBase::msg_body_parse:Message was not receieved entirely. length=%ld,osip_body_len=%ld\n",
                   length, body_len);
            return -1;
        }

        string strBody(start_of_body, body_len);

        /* printf("MsgBase::msg_body_parse:body length=%ld,body=<%s>\n", body_len, start_of_body); */
        return SetBody(strBody.c_str());
    }

#if 0
    string sep_boundary;
    /* find the boundary */
    MsgParam *pParam = content_type.m_listParams.get_byname("boundary");

    if (pParam)
    {
        if (pParam->m_strValue.empty())
        {

            printf("MsgBase::msg_body_parse:find the boundary,param value is not found!\n");
            return -1;
        }

        size_t len = pParam->m_strValue.size();

        sep_boundary = "\n--";  //boundary prefix

        if (pParam->m_strValue[0] == '"' && pParam->m_strValue[len - 1] == '"' && len > 2)
        {
            sep_boundary += string(pParam->m_strValue.c_str() + 1, len - 2);
        }
        else
        {
            sep_boundary += pParam->m_strValue;
        }
    }

    if (sep_boundary.empty())
    {

        printf("MsgBase::msg_body_parse:sep_boundary is empty!\n");
        return -1;
    }

    *next_body = NULL;
    start_of_body = start_of_buf;

    end_of_buf = start_of_buf + length;

    for (;;)
    {
        size_t body_len = 0;

        if (find_next_occurence(sep_boundary.c_str(), start_of_body,
                                &start_of_body, end_of_buf) != 0)
        {
            printf("MsgBase::msg_body_parse:find_next_occurence fail!\n");
            return -1;
        }

        if (find_next_occurence(sep_boundary.c_str(),
                                start_of_body + sep_boundary.size(),
                                &end_of_body, end_of_buf) != 0)
        {
            //point to end_of_buf when last boundary for ZET msg, by tangmin, 2008,05.10
            if (!end_of_body)
            {
                end_of_body = end_of_buf;
            }

//			return -1;
        }

        /* this is the real beginning of body */
        start_of_body = start_of_body + sep_boundary.size() + 1;

        if ('\n' == start_of_body[0] || '\r' == start_of_body[0])
        {
            start_of_body++;
        }

        body_len = end_of_body - start_of_body;

        /* Skip CR before end boundary. */
        if (*(end_of_body - 1) == '\r')
        {
            body_len--;
        }

        string strTemp(start_of_body, body_len);
        int32_t ret = osip_message_set_body_mime(strTemp);

        if (ret != 0)
        {

            printf("MsgBase::msg_body_parse:osip_message_set_body_mime fail!\n");
            return -1;
        }

        if (strncmp(end_of_body + sep_boundary.size(), "--", 2) == 0)
        {
            /* end of all bodies */
            *next_body = end_of_body;
            return 0;
        }

        /* continue on the next body */
        start_of_body = end_of_body;

        //add by tangmin
        if (start_of_body == end_of_buf)
        {
            return 0;
        }

    }

#endif
    /* Unreachable code */

    printf("MsgBase::msg_body_parse:Unreachable code!\n");

    return -1;
}

int32_t MsgBase::msg_set_multiple_header(char *hname, char *hvalue)
{
    char *ptr;                    /* current location of the search */
    char *comma;                  /* This is the separator we are looking for */
    char *begin;                  /* beg of a header */
    char *end;                    /* end of a header */
    char *quote1;                 /* first quote of a pair of quotes   */
    char *quote2;                 /* second quote of a pair of quotes */
    size_t hname_len;

    if (hname == NULL)
    {
        return -1;
    }

    /* Find header based upon lowercase comparison */
    //stk_tolower(hname);

    if (hvalue == NULL)
    {
        return msg_set_header(hname, "");
    }

    ptr = hvalue;
    comma = strchr(ptr, ',');

    hname_len = strlen(hname);

    if (comma == NULL ||
            (hname_len == 6  && 0 == strncasecmp(hname, STK_COMM_ACCEPT, 6)) ||
            (hname_len == 15 && 0 == strncasecmp(hname, STK_COMM_ACCEPT_ENCODING, 15)) ||
            (hname_len == 15 && 0 == strncasecmp(hname, STK_COMM_ACCEPT_LANGUAGE, 15)) ||
            (hname_len == 13 && 0 == strncasecmp(hname, STK_COMM_AUTHORIZATION, 13)) ||
            (hname_len == 4  && 0 == strncasecmp(hname, STK_COMM_CSEQ, 4)) ||
            (hname_len == 16 && 0 == strncasecmp(hname, STK_COMM_CONTENT_ENCODING, 16)) ||
            (hname_len == 16 && 0 == strncasecmp(hname, STK_COMM_CONTENT_LANGUAGE, 16)) ||
            (hname_len == 14 && 0 == strncasecmp(hname, STK_COMM_CONTENT_LENGTH, 14)) ||
            (hname_len == 4  && 0 == strncasecmp(hname, STK_COMM_DATE, 4)) ||
            (hname_len == 10 && 0 == strncasecmp(hname, STK_COMM_USER_AGENT, 10)) ||
            (hname_len == 6  && 0 == strncasecmp(hname, STK_COMM_SERVER, 6)) ||
            (hname_len == 16 && 0 == strncasecmp(hname, STK_COMM_WWW_AUTHENTICATE, 16)) ||
            (hname_len == 4  && 0 == strncasecmp(hname, STK_HTTP_HOST, 4)) ||
            (hname_len == 10 && 0 == strncasecmp(hname, STK_HTTP_CONNECTION, 10)) ||
            (hname_len == 9  && 0 == strncasecmp(hname, STK_RTSP_TRANSPORT, 9))  ||
            (hname_len == 7  && 0 == strncasecmp(hname, STK_RTSP_SESSION, 7))  ||
            (hname_len == 5  && 0 == strncasecmp(hname, STK_COMM_RANGE, 5))  ||
            (hname_len == 5  && 0 == strncasecmp(hname, STK_RTSP_SCALE, 5))  ||
            (hname_len == 8  && 0 == strncasecmp(hname, STK_HTTP_LOCATION, 8)))
        /* there is no multiple header! likely      */
        /* to happen most of the time...            */
        /* or hname is a TEXT-UTF8-TRIM and may     */
        /* contain a comma. this is not a separator */
        /* THIS DOES NOT WORK FOR UNKNOWN HEADER!!!! */
    {
        return msg_set_header(hname, hvalue);
    }

    begin = hvalue;
    end = NULL;
    quote2 = NULL;

    while (comma != NULL)
    {
        quote1 = stk_quote_find(ptr);

        if (quote1 != NULL)
        {
            quote2 = stk_quote_find(quote1 + 1);

            if (quote2 == NULL)
            {
                return -1;    /* quotes comes by pair */
            }

            ptr = quote2 + 1;
        }

        if ((quote1 == NULL) || (quote1 > comma))
        {
            /* We must search for the next comma which is not
               within quotes! */
            end = comma;

            if (quote1 != NULL && quote1 > comma)
            {
                /* comma may be within the quotes */
                /* ,<sip:usera@host.example.com>;methods=\"INVITE,BYE,OPTIONS,ACK,CANCEL\",<sip:userb@host.blah.com> */
                /* we want the next comma after the quotes */
                char *tmp_comma;
                char *tmp_quote1;
                char *tmp_quote2;

                tmp_quote1 = quote1;
                tmp_quote2 = quote2;
                tmp_comma = strchr(comma + 1, ',');

                while (1)
                {
                    if (tmp_comma < tmp_quote1)
                    {
                        break;    /* ok (before to quotes) */
                    }

                    if (tmp_comma < tmp_quote2)
                    {
                        tmp_comma = strchr(tmp_quote2 + 1, ',');
                    }

                    tmp_quote1 = stk_quote_find(tmp_quote2 + 1);

                    if (tmp_quote1 == NULL)
                    {
                        break;
                    }

                    tmp_quote2 = stk_quote_find(tmp_quote1 + 1);

                    if (tmp_quote2 == NULL)
                    {
                        break;    /* probably a malformed message? */
                    }
                }

                comma = tmp_comma;        /* this one is not enclosed within quotes */
            }
            else
            {
                comma = strchr(comma + 1, ',');
            }

            if (comma != NULL)
            {
                ptr = comma + 1;
            }

        }
        else if ((quote1 < comma) && (quote2 < comma))
        {
            /* quotes are located before the comma, */
            /* continue the search for next quotes  */
            ptr = quote2 + 1;
        }
        else if ((quote1 < comma) && (comma < quote2))
        {
            /* if comma is inside the quotes... */
            /* continue with the next comma.    */
            ptr = quote2 + 1;
            comma = strchr(ptr, ',');

            if (comma == NULL)
                /* this header last at the end of the line! */
            {
                /* this one does not need an allocation... */
                if (begin[0] == '\0' || begin[1] == '\0')
                {
                    return 0;    /* empty header */
                }

                stk_clrspace(begin);
                return msg_set_header(hname, begin);
            }
        }

        if (end != NULL)
        {
            if (end - begin + 1 < 2)
            {
                return -1;
            }

            char avalue[1024] = "";

            if (end - begin < 1024)
            {
                stk_clrncpy(avalue, begin, end - begin);
            }

            /* really store the header in the sip structure */
            int32_t ret = msg_set_header(hname, avalue);

            if (ret != 0)
            {
                return -1;
            }

            begin = end + 1;
            end = NULL;

            if (comma == NULL)
                /* this header last at the end of the line! */
            {
                /* this one does not need an allocation... */
                if (begin[0] == '\0' || begin[1] == '\0')
                {
                    return 0;    /* empty header */
                }

                stk_clrspace(begin);

                if (msg_set_header(hname, begin) != 0)
                {
                    return -1;
                }

                return 0;
            }
        }
    }

    return -1;
}

#if 0
int32_t MsgBase::msg_set_multiple_header(char *hname, char *hvalue)
{
    char *ptr;                    /* current location of the search */
    char *comma;                  /* This is the separator we are looking for */
    char *begin;                  /* beg of a header */
    char *end;                    /* end of a header */
    char *quote1;                 /* first quote of a pair of quotes   */
    char *quote2;                 /* second quote of a pair of quotes */
    char separator;
    size_t hname_len;

    if (hname == NULL)
    {
        return -1;
    }

    /* Find header based upon lowercase comparison */
    //stk_tolower(hname);

    if (hvalue == NULL)
    {
        return msg_set_header(hname, "");
    }

    ptr = hvalue;
    comma = strchr(ptr, ',');

    if (comma)
    {
        separator = ',';
    }
    else
    {
        comma = strchr(ptr, ';');

        if (comma)
        {
            separator = ';';
        }
    }

    hname_len = strlen(hname);

    if (comma == NULL ||
            (hname_len == 6  && strncasecmp(hname, STK_COMM_ACCEPT, 6)) ||
            (hname_len == 15 && strncasecmp(hname, STK_COMM_ACCEPT_ENCODING, 15)) ||
            (hname_len == 15 && strncasecmp(hname, STK_COMM_ACCEPT_LANGUAGE, 15)) ||
            (hname_len == 13 && strncasecmp(hname, STK_COMM_AUTHORIZATION, 13)) ||
            (hname_len == 4  && strncasecmp(hname, STK_COMM_CSEQ, 4)) ||
            (hname_len == 16 && strncasecmp(hname, STK_COMM_CONTENT_ENCODING, 16)) ||
            (hname_len == 16 && strncasecmp(hname, STK_COMM_CONTENT_LANGUAGE, 16)) ||
            (hname_len == 14 && strncasecmp(hname, STK_COMM_CONTENT_LENGTH, 14)) ||
            (hname_len == 12 && strncasecmp(hname, STK_COMM_CONTENT_TYPE, 12)) ||
            (hname_len == 4  && strncasecmp(hname, STK_COMM_DATE, 4)) ||
            (hname_len == 10 && strncasecmp(hname, STK_COMM_USER_AGENT, 10)) ||
            (hname_len == 6  && strncasecmp(hname, STK_COMM_SERVER, 6)) ||
            (hname_len == 16 && strncasecmp(hname, STK_COMM_WWW_AUTHENTICATE, 16)) ||
            (hname_len == 4  && strncasecmp(hname, STK_HTTP_HOST, 4)) ||
            (hname_len == 10 && strncasecmp(hname, STK_HTTP_CONNECTION, 10)) ||
            (hname_len == 9  && strncasecmp(hname, STK_RTSP_TRANSPORT, 9))  ||
            (hname_len == 7  && strncasecmp(hname, STK_RTSP_SESSION, 7))  ||
            (hname_len == 5  && strncasecmp(hname, STK_COMM_RANGE, 5))  ||
            (hname_len == 5  && strncasecmp(hname, STK_RTSP_SCALE, 5))  ||
            (hname_len == 8  && strncasecmp(hname, STK_HTTP_LOCATION, 8)))
        /* there is no multiple header! likely      */
        /* to happen most of the time...            */
        /* or hname is a TEXT-UTF8-TRIM and may     */
        /* contain a comma. this is not a separator */
        /* THIS DOES NOT WORK FOR UNKNOWN HEADER!!!! */
    {
        return msg_set_header(hname, hvalue);
    }

    begin = hvalue;
    end = NULL;
    quote2 = NULL;

    while (comma != NULL)
    {
        quote1 = stk_quote_find(ptr);

        if (quote1 != NULL)
        {
            quote2 = stk_quote_find(quote1 + 1);

            if (quote2 == NULL)
            {
                return -1;    /* quotes comes by pair */
            }

            ptr = quote2 + 1;
        }

        if ((quote1 == NULL) || (quote1 > comma))
        {
            /* We must search for the next comma which is not
               within quotes! */
            end = comma;

            if (quote1 != NULL && quote1 > comma)
            {
                /* comma may be within the quotes */
                /* ,<sip:usera@host.example.com>;methods=\"INVITE,BYE,OPTIONS,ACK,CANCEL\",<sip:userb@host.blah.com> */
                /* we want the next comma after the quotes */
                char *tmp_comma;
                char *tmp_quote1;
                char *tmp_quote2;

                tmp_quote1 = quote1;
                tmp_quote2 = quote2;
                tmp_comma = strchr(comma + 1, separator);

                while (1)
                {
                    if (tmp_comma < tmp_quote1)
                    {
                        break;    /* ok (before to quotes) */
                    }

                    if (tmp_comma < tmp_quote2)
                    {
                        tmp_comma = strchr(tmp_quote2 + 1, separator);
                    }

                    tmp_quote1 = stk_quote_find(tmp_quote2 + 1);

                    if (tmp_quote1 == NULL)
                    {
                        break;
                    }

                    tmp_quote2 = stk_quote_find(tmp_quote1 + 1);

                    if (tmp_quote2 == NULL)
                    {
                        break;    /* probably a malformed message? */
                    }
                }

                comma = tmp_comma;        /* this one is not enclosed within quotes */
            }
            else
            {
                comma = strchr(comma + 1, separator);
            }

            if (comma != NULL)
            {
                ptr = comma + 1;
            }

        }
        else if ((quote1 < comma) && (quote2 < comma))
        {
            /* quotes are located before the comma, */
            /* continue the search for next quotes  */
            ptr = quote2 + 1;
        }
        else if ((quote1 < comma) && (comma < quote2))
        {
            /* if comma is inside the quotes... */
            /* continue with the next comma.    */
            ptr = quote2 + 1;
            comma = strchr(ptr, separator);

            if (comma == NULL)
                /* this header last at the end of the line! */
            {
                /* this one does not need an allocation... */
                if (begin[0] == '\0' || begin[1] == '\0')
                {
                    return 0;    /* empty header */
                }

                stk_clrspace(begin);
                return msg_set_header(hname, begin);
            }
        }

        if (end != NULL)
        {
            if (end - begin + 1 < 2)
            {
                return -1;
            }

            char avalue[1024] = "";

            if (end - begin < 1024)
            {
                stk_clrncpy(avalue, begin, end - begin);
            }

            /* really store the header in the sip structure */
            int32_t ret = msg_set_header(hname, avalue);

            if (ret != 0)
            {
                return -1;
            }

            begin = end + 1;
            end = NULL;

            if (comma == NULL)
                /* this header last at the end of the line! */
            {
                /* this one does not need an allocation... */
                if (begin[0] == '\0' || begin[1] == '\0')
                {
                    return 0;    /* empty header */
                }

                stk_clrspace(begin);

                if (msg_set_header(hname, begin) != 0)
                {
                    return -1;
                }

                return 0;
            }
        }
    }

    return -1;
}
#endif

int32_t MsgBase::msg_set_header(const char *hname, const char *hvalue)
{
    if (hname == NULL)
    {
        return -1;
    }

    if (hvalue == NULL)
    {
        hvalue = "";
    }

    /* some headers are analysed completely      */
    /* this method is used for selective parsing */

    string pname = hname;
    transform(pname.begin(), pname.end(), pname.begin(), ::tolower);
    unsigned int hash = Hash(pname.c_str());
    hash = hash % HASH_TABLE_SIZE;
    int index = new_hdr_ref_table[hash];

    if ((index > 0) && (0 == strcasecmp(header_pconfig[index].hdrname, hname)))
    {
        /* 注意这里调用方式 */
        int ret = (this->*(header_pconfig[index].setheader))(hvalue);

        if (ret == -1)
        {
            printf("Could not set header: \"%s\" %s\n", hname, hvalue);
            return -1;
        }

        return 0;
    }

    //	/* unknown header */
    //	if (SetHeader(hname, hvalue) != 0)
    //	{
    //		printf("Could not set unknown header\n");
    //		return -1;
    //	}

    return 0;
}

int32_t MsgBase::SetBody(const char *szValue)
{
    if (szValue == NULL || szValue[0] == '\0')
    {
        return 0;
    }

    Body *body = new Body(szValue, strlen(szValue));

    if (NULL == body)
    {
        return -1;
    }

    if (bodies.add(body) != 0)
    {
        delete body;
        return -1;
    }


    /* 从头域解析的值与实际的长度可能不一致 */
    m_iContentLength = 0;

    int32_t pos = 0;

    while (!bodies.eol(pos))
    {
        Body *body = (Body *)bodies.get(pos++);

        if (body == NULL)
        {
            continue;
        }

        m_iContentLength += body->m_strBody.size();
    }

    SetContentLength(m_iContentLength);

    return 0;
}

int32_t MsgBase::SetBody(const Body &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    Body *body = new Body(field);
    bodies.add(body);
    m_iMessageProperty = 2;

    return 0;
}

Body *MsgBase::GetBody(int32_t pos)
{
    if (bodies.size() <= 0 ||
            (pos < 0 && pos != -1) ||
            pos >= bodies.size())
    {
        return NULL;
    }

    if (-1 == pos)
    {
        return (Body *)bodies.get(bodies.size() - 1);
    }

    return (Body *)bodies.get(pos);
}

string  MsgBase::GetBody()
{
    string str = "";

    MsgField *field = (MsgField *)bodies.get(0);

    if (field)
    {
        field->to_str(str);
    }

    return str;
}


int32_t MsgBase::SetMethod(const char *szValue)
{
    m_strMethod = szValue;
    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetReqUrl(const char *szValue)
{
    m_strReqUrl        = szValue;
    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetVersion(const char *szValue)
{
    m_strVersion = szValue;
    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetAccept(const char *szValue)
{
    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetAcceptEncoding(const char *szValue)
{
    if (szValue == NULL || szValue[0] == '\0')
    {
        return 0;
    }

    AcceptEncoding *accept_encoding = new AcceptEncoding(szValue);
    if (NULL == accept_encoding)
    {
        return -1;
    }

    if (accept_encodings.add(accept_encoding) != 0)
    {
        delete accept_encoding;
        return -1;
    }

    m_iMessageProperty = 2;

    return 0;

}

string  MsgBase::GetAcceptEncoding()
{
    string str = "";

    MsgField *field = (MsgField *)accept_encodings.get(0);
    if (field)
    {
        field->to_str(str);
    }

    return str;
}

int32_t MsgBase::SetAcceptLanguage(const char *szValue)
{
    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetAuthorization(const char *szValue)
{
    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetCSeq(const char *szValue)
{
    if (cseq.parse(szValue, strlen(szValue)) < 0)
    {
        return -1;
    }

    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetCSeq(const CSeq &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    cseq = field;
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetCSeq()
{
    string str;
    cseq.to_str(str);

    return str;
}


int32_t MsgBase::SetContentType(const char *szValue)
{
    if (content_type.parse(szValue, strlen(szValue)) < 0)
    {
        return -1;
    }

    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetContentType(const ContentType &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    content_type = field;
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetContentType()
{
    string str;
    content_type.to_str(str);

    return str;
}

int32_t MsgBase::SetContentLength(const char *szValue)
{
    if (content_length.parse(szValue, strlen(szValue)) == 0)
    {
        m_iContentLength = atoi(szValue);
        m_iMessageProperty = 2;
        return 0;
    }

    return -1;
}

int32_t MsgBase::SetContentLength(const int32_t length)
{
    char szLen[10] = {0};

    snprintf(szLen, 10, "%d", length);

    return SetContentLength(szLen);
}

string MsgBase::GetContentLength()
{
    string str;

    content_length.to_str(str);
    return str;
}

int32_t MsgBase::GetContentLength_int()
{
    return m_iContentLength;
}

int32_t MsgBase::SetContentEncoding(const char *szValue)
{
    if (content_encoding.parse(szValue, strlen(szValue)) < 0)
    {
        return -1;
    }

    m_iMessageProperty = 2;
    return 0;
}

string MsgBase::GetContentEncoding()
{
    string str;

    content_encoding.to_str(str);
    return str;
}

int32_t MsgBase::SetContentLanguage(const char *szValue)
{
    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetContentBase(const char *szValue)
{
    if (content_base.parse(szValue, strlen(szValue)) == 0)
    {
        m_iMessageProperty = 2;
        return 0;
    }

    return -1;
}

int32_t MsgBase::SetContentBase(const ContentBase &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    content_base = field;
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetContentBase()
{
    string str;

    content_base.to_str(str);
    return str;
}

int32_t MsgBase::SetDate(const char *szValue)
{
    if (date.parse(szValue, strlen(szValue)) < 0)
    {
        return -1;
    }

    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetDate(const Date &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    date = field;
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetDate()
{
    string str;
    date.to_str(str);

    return str;
}

int32_t MsgBase::SetServer(const char *szValue)
{
    if (server.parse(szValue, strlen(szValue)) < 0)
    {
        return -1;
    }

    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetServer(const Server &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    server = field;
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetServer()
{
    string str;
    server.to_str(str);

    return str;
}

int32_t MsgBase::SetPublic(const char *szValue)
{
    if (szValue == NULL || szValue[0] == '\0')
    {
        return 0;
    }

    Public *_public = new Public(szValue);

    if (NULL == _public)
    {
        return -1;
    }

    if (publics.add(_public) != 0)
    {
        delete _public;
        return -1;
    }

    m_iMessageProperty = 2;

    return 0;
}

int32_t MsgBase::SetPublic(const Public &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    Public *_public = new Public(field);

    if (!_public)
    {
        return -1;
    }

    publics.add(_public);
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetPublic()
{
    string str = "";

    MsgField *field = (MsgField *)publics.get(0);

    if (field)
    {
        field->to_str(str);
    }

    return str;
}

int32_t MsgBase::SetAllow(const char *szValue)
{
    if (szValue == NULL || szValue[0] == '\0')
    {
        return 0;
    }

    Allow *allow = new Allow(szValue);
    if (NULL == allow)
    {
        return -1;
    }

    if (allows.add(allow) != 0)
    {
        delete allow;
        return -1;
    }

    m_iMessageProperty = 2;

    return 0;
}

int32_t MsgBase::SetAllow(const Allow &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    Allow *allow = new Allow(field);
    if (!allow)
    {
        return -1;
    }

    allows.add(allow);
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetAllow()
{
    string str = "";

    MsgField *field = (MsgField *)allows.get(0);
    if (field)
    {
        field->to_str(str);
    }

    return str;
}

int32_t MsgBase::SetUserAgent(const char *szValue)
{
    if (user_agent.parse(szValue, strlen(szValue)) < 0)
    {
        return -1;
    }

    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetWwwAuthenticate(const char *szValue)
{
    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetCacheControl(const char *szValue)
{
    if (cache_controls.parse(szValue, strlen(szValue)) < 0)
    {
        return -1;
    }

    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetCacheControl(const CacheControl &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    cache_controls = field;
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetCacheControl()
{
    string str;
    cache_controls.to_str(str);

    return str;
}

int32_t MsgBase::SetRange(const char *szValue)
{
    if (ranges.parse(szValue, strlen(szValue)) < 0)
    {
        return -1;
    }

    m_iMessageProperty = 2;
    return 0;
}

int32_t MsgBase::SetRange(const Range &field)
{
    if (!field.isvalid())
    {
        return -1;
    }

    ranges = field;
    m_iMessageProperty = 2;

    return 0;
}

string MsgBase::GetRange()
{
    string str;
    ranges.to_str(str);

    return str;
}

string MsgBase::GetUserAgent()
{
    string str;
    user_agent.to_str(str);
    return str;
}
